package jwdt.utils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;

public class VelocityUtils {
	
	/**
	 * MARKER
	 */
	public static final String MARKER_JWDT_BEGIN = "[JWDT.DEVTOOLS.PROTECTIVE.CONTENT.BEGIN]";
	public static final String MARKER_JWDT_END = "[JWDT.DEVTOOLS.PROTECTIVE.CONTENT.END]";
	
	/**
	 * MARKER SPLIT
	 */
	public static final String MARKER_BEFORE_CONTENT  = "MARKER_BEFORE_CONTENT";
	public static final String MARKER_CONTENT  = "MARKER_CONTENT";
	public static final String MARKER_AFTER_CONTENT  = "MARKER_AFTER_CONTENT";

	/**
	 * 生成文件，如果已存在，只修改预定部分
	 * @param templateFile
	 * @param outFilePath
	 * @param parameters
	 * @throws IOException
	 */
	public static void evaluate(String templateFile , String outFilePath , Map<String,Object> parameters) throws IOException{
		File outFile = new File(outFilePath);
		if(outFile.exists()){
			//文件已存在，只修改预定部分
			Map<String,String> srcMap = splitFile4Marker(outFile);
			//判断文件中是否正常使用了MARKER，如果为正常使用，按模版刷新文件
			if("".equals(srcMap.get(MARKER_AFTER_CONTENT))){
				String newContent = evaluate(templateFile, parameters);				
				Writer writer=new PrintWriter(outFile);
				writer.write(newContent);
				writer.flush();
				writer.close();
			}else{
				String newContent = evaluate(templateFile, parameters);
				Map<String,String> newMap = splitString4Marker(newContent);
				newContent = srcMap.get(MARKER_BEFORE_CONTENT) 
							+ newMap.get(MARKER_CONTENT) 
							+ srcMap.get(MARKER_AFTER_CONTENT);
				Writer writer=new PrintWriter(outFile);
				writer.write(newContent);
				writer.flush();
				writer.close();
			}			
		}else{
			//文件不存在，直接生成
			VelocityEngine velocityEngine=new VelocityEngine();
			velocityEngine.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, VelocityUtils.class.getResource("").getPath());
			velocityEngine.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
			velocityEngine.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");		

			VelocityContext velocityContext=new VelocityContext();
			for(String key : parameters.keySet()){
				velocityContext.put(key, parameters.get(key));	
			}
			
			Writer writer=new PrintWriter(outFile);
			
			velocityEngine.evaluate(velocityContext, writer, Velocity.class.getName(), getTemplateContents(templateFile));
			
			writer.flush();
			writer.close();	
		}		
	}
	
	/**
	 * 获取预生产文件内容
	 * @param templateFile
	 * @param parameters
	 * @return
	 * @throws IOException
	 */
	public static String evaluate(String templateFile , Map<String,Object> parameters) throws IOException{
		VelocityEngine velocityEngine=new VelocityEngine();
		velocityEngine.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, VelocityUtils.class.getResource("").getPath());
		velocityEngine.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
		velocityEngine.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");		

		VelocityContext velocityContext=new VelocityContext();
		for(String key : parameters.keySet()){
			velocityContext.put(key, parameters.get(key));	
		}
				
		StringWriter writer=new StringWriter();
		
		velocityEngine.evaluate(velocityContext, writer, Velocity.class.getName(), getTemplateContents(templateFile));
		
		return 	writer.toString();
	}
	
	/**
	 * 根据Marker拆分文件内容
	 * @param file
	 * @return
	 * @throws IOException
	 */
	private static Map<String,String> splitFile4Marker(File file)throws IOException{
		Map<String,String> map = new HashMap<String, String>();
		BufferedReader br = new BufferedReader(new FileReader(file));
		String tmpStr = "";
		String beforeContent = "";
		String content = "";
		String afterContent = "";
		int split = 0;
		while((tmpStr = br.readLine()) != null){
			if(tmpStr.indexOf(MARKER_JWDT_END) > -1){
				if(split == 1){split++;}
			}
			
			if(split == 0){
				beforeContent+=tmpStr;
				beforeContent+="\n";
			}else if(split == 1){
				content+=tmpStr;
				content+="\n";
			}else {
				afterContent+=tmpStr;
				afterContent+="\n";
			}
			
			if(tmpStr.indexOf(MARKER_JWDT_BEGIN) > -1){
				if(split == 0){split++;}
			}			
		}
		map.put(MARKER_BEFORE_CONTENT, beforeContent);
		map.put(MARKER_CONTENT, content);
		map.put(MARKER_AFTER_CONTENT, afterContent);
		return map;
	}
	
	/**
	 * 根据Marker拆分内容
	 * @param str
	 * @return
	 * @throws IOException
	 */
	private static Map<String,String> splitString4Marker(String str)throws IOException{
		Map<String,String> map = new HashMap<String, String>();
		StringReader sr = new StringReader(str);
		BufferedReader br = new BufferedReader(sr);
		String tmpStr = "";
		String beforeContent = "";
		String content = "";
		String afterContent = "";
		int split = 0;
		while((tmpStr = br.readLine()) != null){
			if(tmpStr.indexOf(MARKER_JWDT_END) > -1){
				if(split == 1){split++;}
			}
			
			if(split == 0){
				beforeContent+=tmpStr;
				beforeContent+="\n";
			}else if(split == 1){
				content+=tmpStr;
				content+="\n";
			}else {
				afterContent+=tmpStr;
				afterContent+="\n";
			}
			
			if(tmpStr.indexOf(MARKER_JWDT_BEGIN) > -1){
				if(split == 0){split++;}
			}			
		}
		map.put(MARKER_BEFORE_CONTENT, beforeContent);
		map.put(MARKER_CONTENT, content);
		map.put(MARKER_AFTER_CONTENT, afterContent);
		return map;
	}
		
	/**
	 * 获取模版文件内容
	 * @param templateName
	 * @return
	 * @throws IOException
	 */
	private static String getTemplateContents(String templateName) throws IOException {
		InputStream is = VelocityUtils.class.getClassLoader().getResourceAsStream(templateName);
		if (null == is) {
			return null;
		}
		try {
			InputStreamReader reader = new InputStreamReader(is);
			char[] buffer = new char[1024];
			StringWriter writer = new StringWriter();
			int bytes_read;
			while ((bytes_read = reader.read(buffer)) != -1) {
				writer.write(buffer, 0, bytes_read);
			}
			return (writer.toString());
		} finally {
			if (null != is) {
				is.close();
			}
		}
	}
	
}
